package output;

import PackagePoseidon.AngulationData;
import PackagePoseidon.DistanceData;
import PackagePoseidon.EnvironmentData;
import PackagePoseidon.ForceData;
import PackagePoseidon.RobotData;
import PackagePoseidon.SpeedData;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;

/**
 * Michel Uncini 01/08/2010
 *
 * The class ControlPanel2 is used to have an user-friendly output GUI; it owns
 * three panels, a lot of text fields and some indicators for everything is
 * needed for the project (included the physics, the robot instant informations,
 * the actual direction of the joystick).
 *
 */
public class ControlPanel2 extends JPanel implements Observer {

	//Control panel is a JPanel; the constructor builds the panel
    JPanel robotP = new JPanel();
    JPanel environmentP = new JPanel();
    JPanel forceP = new JPanel();

    //Environment
    JTextField waterDensityTextField = new JTextField("0 ");
	JTextField frictionAreaReferenceTextField = new JTextField("0 ");
	JTextField frictionDragCoefficientTextField = new JTextField("0 ");

    //Force
    JTextField liftPushUpTextField = new JTextField("0");
	JTextField gravityPushDownTextField = new JTextField("0 ");
	JTextField impulsePushTextField = new JTextField("0 ");
	JTextField frictionPushTextField = new JTextField("0 ");

    //Robot
    JTextField robotMaxSpeedTextField = new JTextField("0 ");
    JTextField robotMassTextField = new JTextField("0 ");
    JTextField robotHeightTextField = new JTextField("0 ");
    JTextField robotLenghtTextField = new JTextField("0 ");
    JTextField robotPayloadTextField = new JTextField("0 ");
    JTextField robotThrustForwardTextField = new JTextField("0 ");
    JTextField robotThrustLateralTextField = new JTextField("0 ");
    JTextField robotThrustVerticalTextField = new JTextField("0 ");
    JTextField robotMaxWorkingDepthTextField = new JTextField("0 ");
    JTextField robotVolumeTextField = new JTextField("0 ");
    JTextField robotDensityTextField = new JTextField("0 ");


    /**
     * Michel Uncini 01/08/2010
     *
     * The constructor is used to launch all the needed methods in order to
     * build the Output GUI, and to build a tabbedPane for an easier navigation.
     *
     * @param
     */
	public ControlPanel2 () {

        this.setLayout(new GridLayout(1,0) );
        this.setPreferredSize(new Dimension(250, 500));

        //Creates all the objects in the panels
        initEnvironmentP();
        initRobotP();
        initForceP();
        initVelocity();

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Robot",null, robotP, " Robot");
        tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);
        tabbedPane.addTab("Environment", null, environmentP, "Environment");
        tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);
        tabbedPane.addTab("Force", null, forceP, "Force");
        tabbedPane.setMnemonicAt(2, KeyEvent.VK_3);
        tabbedPane.addTab("Info", null, infoP, "Info");
        tabbedPane.setMnemonicAt(3, KeyEvent.VK_4);
        this.add(tabbedPane);
	}


    /**
     * Michel Uncini 01/08/2010
     *
     * The method creates and initializes the labels and the text fields
     * regarding the parameters of the robot.
     *
     * @param
     * @return
     */
    private void initRobotP(){

        JLabel robotMaxSpeedLabel = new JLabel("robotMaxSpeedLabel ");
        JLabel robotMassLabel = new JLabel("robotMassLabel ");
        JLabel robotHeightLabel = new JLabel("robotHeightLabel ");
        JLabel robotWidthLabel = new JLabel("robotWidthLabels ");
        JLabel robotPayloadLabel = new JLabel("robotPayloadLabel ");
        JLabel robotThrustForwardLabel = new JLabel("robotThrustForwardLabel ");
        JLabel robotThrustLateralLabel = new JLabel("robotThrustLateralLabel ");
        JLabel robotThrustVerticalLabel = new JLabel("robotThrustVerticalLabel ");
        JLabel robotMaxWorkingDepthLabel = new JLabel("robotMaxWorkingDepthLabel ");
        JLabel robotVolumeLabel = new JLabel("robotVolumeLabel ");
        JLabel robotDensityLabel = new JLabel("robotDensityLabel ");


        robotP.setLayout(new GridLayout(11,2));
        robotP.setPreferredSize(new Dimension(100,900));

        robotP.add(robotMaxSpeedLabel);
        robotP.add(robotMaxSpeedTextField);
        robotP.add(robotMassLabel);
        robotP.add(robotMassTextField);
        robotP.add(robotHeightLabel);
        robotP.add(robotHeightTextField);
        robotP.add(robotWidthLabel);
        robotP.add(robotLenghtTextField);
        robotP.add(robotPayloadLabel);
        robotP.add(robotPayloadTextField);
        robotP.add(robotThrustForwardLabel);
        robotP.add(robotThrustForwardTextField);
        robotP.add(robotThrustLateralLabel);
        robotP.add(robotThrustLateralTextField);
        robotP.add(robotThrustVerticalLabel);
        robotP.add(robotThrustVerticalTextField);
        robotP.add(robotMaxWorkingDepthLabel);
        robotP.add(robotMaxWorkingDepthTextField);
        robotP.add(robotVolumeLabel);
        robotP.add(robotVolumeTextField);
        robotP.add(robotDensityLabel);
        robotP.add(robotDensityTextField);
    }

    /**
     * Michel Uncini 01/08/2010
     *
     * The method creates and initializes the labels and the text fields
     * regarding the environment.
     *
     * @param
     * @return
     */
    private void initEnvironmentP(){

        JLabel waterDensityLabel = new JLabel("waterDensityLabel ");
        JLabel frictionAreaReferenceLabel = new JLabel("frictionAreaReferenceLabel ");
        JLabel frictionDragCoefficientLabel = new JLabel("frictionDragCoefficientLabel ");


        environmentP.setLayout(new GridLayout(3,2));

        environmentP.add(waterDensityLabel);
        environmentP.add(waterDensityTextField);
        environmentP.add(frictionAreaReferenceLabel);
        environmentP.add(frictionAreaReferenceTextField);
        environmentP.add(frictionDragCoefficientLabel);
        environmentP.add(frictionDragCoefficientTextField);
    }

    /**
     * Michel Uncini 01/08/2010
     *
     * The method creates and initializes the labels and the text fields
     * regarding the applied forces.
     *
     * @param
     * @return
     */
    private void initForceP(){
        JLabel liftPushUpLabel = new JLabel("liftPushUp ");
        JLabel gravityPushDownLabel = new JLabel("gravityPushDownLabel ");
        JLabel impulsePushLabel = new JLabel("impulsePushLabel ");
        JLabel frictionPushLabel = new JLabel("frictionPushLabel ");


        forceP.setLayout(new GridLayout(4,2));

        forceP.add(liftPushUpLabel);
        forceP.add(liftPushUpTextField);
        forceP.add(gravityPushDownLabel);
        forceP.add(gravityPushDownTextField);
        forceP.add(impulsePushLabel);
        forceP.add(impulsePushTextField);
        forceP.add(frictionPushLabel);
        forceP.add(frictionPushTextField);
    }

    //new JPanels for better understanding and a more user-friendly interface
    JPanel infoP = new JPanel();
    private ControlPanelSpeed controlPanelSpeed;
    private ControlPanelAngulation controlPanelAngulation;
    private ControlPanelDistance controlPanelDistance;

    /**
     * Michel Uncini 01/08/2010
     *
     * This internal class regards the control panel used for the speed of the
     * robot.
     *
     */
    public class ControlPanelSpeed extends JPanel{

        public JTextField speedFieldX;
        public JTextField speedFieldY;
        public JTextField speedFieldZ;

        /**
         * Michel Uncini 01/08/2010
         *
         * The constructor creates all the needed fields.
         *
         * @param
         */
        public ControlPanelSpeed() {
            setLayout(new GridLayout(1,3) );
            speedFieldX = new JTextField("0");
            speedFieldY = new JTextField("0");
            speedFieldZ = new JTextField("0");
            this.add(speedFieldX);
            this.add(speedFieldY);
            this.add(speedFieldZ);
        }
    }

    /**
     * Michel Uncini 01/08/2010
     *
     * This internal class regards the control panel used for the angulation of
     * the robot (from its initial position).
     *
     */
    public class ControlPanelAngulation extends JPanel{

        public JTextField angulationFieldX;
        public JTextField angulationFieldY;
        public JTextField angulationFieldZ;

        /**
         * Michel Uncini 01/08/2010
         *
         * The constructor creates all the needed fields.
         *
         * @param
         */
        public ControlPanelAngulation() {
            setLayout(new GridLayout(1,3) );
            angulationFieldX = new JTextField("0");
            angulationFieldY = new JTextField("0");
            angulationFieldZ = new JTextField("0");
            this.add(angulationFieldX);
            this.add(angulationFieldY);
            this.add(angulationFieldZ);
        }

    }

    /**
     * Michel Uncini 01/08/2010
     *
     * This internal class regards the control panel used for the distance of
     * the robot (from its initial position).
     *
     */
    public class ControlPanelDistance extends JPanel{

        public JTextField distantFieldX;
        public JTextField distantFieldY;
        public JTextField distantFieldZ;

        /**
         * Michel Uncini 01/08/2010
         *
         * The constructor creates all the needed fields.
         *
         * @param
         */
        public ControlPanelDistance() {
            setLayout(new GridLayout(1,3) );
            distantFieldX = new JTextField("0");
            distantFieldY = new JTextField("0");
            distantFieldZ = new JTextField("0");
            this.add(distantFieldX);
            this.add(distantFieldY);
            this.add(distantFieldZ);
        }

    }

    /**
     * Michel Uncini 01/08/2010
     *
     * The method creates and initializes the labels and the text fields
     * regarding the speed, the angulation and the distance.
     *
     * @param
     * @return
     */
    private void initVelocity(){

        JLabel speedLabel = new JLabel("Speed: ");
        JLabel angulationLabel = new JLabel("Angulation: ");
        JLabel distanceLabel = new JLabel("Distance: ");

        //Control Panels
        controlPanelSpeed = new ControlPanelSpeed();
        controlPanelAngulation = new ControlPanelAngulation();
        controlPanelDistance = new ControlPanelDistance();

        //Adds labels and text fields
        infoP.setLayout(new GridLayout(3,2));
        infoP.add(speedLabel);
        infoP.add(controlPanelSpeed);
        infoP.add(angulationLabel);
        infoP.add(controlPanelAngulation);
        infoP.add(distanceLabel);
        infoP.add(controlPanelDistance);
    }


    /**
     * Francesco Lilli/MIchel Uncini 01/08/2010
     *
     * The method onNewData is used when something new is written into OPS; the
     * new data can be of every type, but in any case it has to be written into
     * the output fields as soon as the method is called.
     * With this method is possible to understand what new data we're talking
     * of, so that we always can write the correct information into the correct
     * field/fields.
     *
     * @param
     * @return
     */
    private void onNewData(Object data) {

        
        if (data instanceof SpeedData){
            SpeedData dataSpe = (SpeedData)data;

            controlPanelSpeed.speedFieldX.setText(dataSpe.xSpeed);
            controlPanelSpeed.speedFieldY.setText(dataSpe.ySpeed);
            controlPanelSpeed.speedFieldZ.setText(dataSpe.zSpeed);
        }

        if (data instanceof AngulationData){
            AngulationData dataAng = (AngulationData)data;

            controlPanelAngulation.angulationFieldX.setText(dataAng.xAngulation);
            controlPanelAngulation.angulationFieldY.setText(dataAng.yAngulation);
            controlPanelAngulation.angulationFieldZ.setText(dataAng.zAngulation);
        }
        
        if (data instanceof DistanceData){
            DistanceData dataDis = (DistanceData)data;

            controlPanelDistance.distantFieldX.setText(dataDis.xDistance);
            controlPanelDistance.distantFieldY.setText(dataDis.yDistance);
            controlPanelDistance.distantFieldZ.setText(dataDis.zDistance);
        }

        if (data instanceof EnvironmentData){
            EnvironmentData dataEnv = (EnvironmentData)data;

            waterDensityTextField.setText(dataEnv.waterDensity);
            frictionAreaReferenceTextField.setText(dataEnv.frictionAreaReference);
            frictionDragCoefficientTextField.setText(dataEnv.frictionDragCoefficient);
        }
        
        if (data instanceof ForceData){
            ForceData dataFor = (ForceData)data;

            liftPushUpTextField.setText(dataFor.liftPushUp);
            gravityPushDownTextField.setText(dataFor.gravityPushDown);
            impulsePushTextField.setText(dataFor.impulsePush);
            frictionPushTextField.setText(dataFor.frictionPush);
        }

        if (data instanceof RobotData){
            RobotData dataRob = (RobotData)data;

            robotMaxSpeedTextField.setText(dataRob.robotMaxSpeed);
            robotMassTextField.setText(dataRob.robotMass);
            robotHeightTextField.setText(dataRob.robotHeight);
            robotLenghtTextField.setText(dataRob.robotLenght);
            robotPayloadTextField.setText(dataRob.robotPayload);
            robotThrustForwardTextField.setText(dataRob.robotThrustForwardForce);
            robotThrustLateralTextField.setText(dataRob.robotThrustLateralForce);
            robotThrustVerticalTextField.setText(dataRob.robotThrustVerticalForce);
            robotMaxWorkingDepthTextField.setText(dataRob.maximumWorkingDepth);
            robotVolumeTextField.setText(dataRob.robotVolume);
            robotDensityTextField.setText(dataRob.robotDensity);
        }
    }

    /**
     * Francesco Lilli/Michel Uncini 01/08/2010
     *
     * The method updates the status of the control panel through an observer.
     *
     * @param   o - an observable object.
     *        arg - an object.
     * @return
     */
    public void update(Observable o, Object arg){
        onNewData(arg);
    }
}
